package com.sneakxy.mybatis.commons.repository.query.executor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.scripting.xmltags.IfSqlNode;
import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;
import org.apache.ibatis.scripting.xmltags.WhereSqlNode;
import org.apache.ibatis.session.Configuration;

import com.sneakxy.mybatis.commons.orm.MybatisEntityManager;
import com.sneakxy.mybatis.commons.orm.generation.GenerationManager;
import com.sneakxy.mybatis.commons.orm.mapping.MybatisColumn;
import com.sneakxy.mybatis.commons.repository.query.parser.MybatisPartTree;

/**
 * @author 潜行的青衣
 * @param <T>
 */
public class FindAllByIdsRepositoryExecutor<T> extends AbstractRepositoryExecutor<List<T>> {

	/**
	 * @param entityManager
	 * @param loader
	 * @param method
	 * @param type
	 */
	public FindAllByIdsRepositoryExecutor(MybatisEntityManager entityManager, Class<?> loader, String method,
			Class<?>... type) {
		super(entityManager, loader, method, type);
	}

	/**
	 * @param entityManager
	 * @param method
	 */
	public FindAllByIdsRepositoryExecutor(MybatisEntityManager entityManager, Method method) {
		super(entityManager, method);
	}

	/* (non-Javadoc)
	 * @see com.sneakxy.mybatis.commons.repository.query.executor.RepositoryExecutor#execute(java.lang.Object[])
	 */
	@Override
	public List<T> execute(Object... parameters) {
		Object parameterObject = this.createParameterObject(parameters, false);
		return this.getEntityManager().getSqlSessionTemplate().selectList(getStatement(), parameterObject);
	}

	/* (non-Javadoc)
	 * @see com.sneakxy.mybatis.commons.repository.query.executor.AbstractRepositoryExecutor#onBuildStatment()
	 */
	@Override
	protected void onBuildStatment() {
		GenerationManager generationManager = this.getEntityManager().getGenerationManager();
		StringBuilder sqlBuilder = new StringBuilder();
		List<MybatisColumn> columns = this.getEntityManager().getEntityColumns(MybatisPartTree.GENERIC_NAME_PREFIX + "1");
		Iterator<MybatisColumn> it = columns.iterator();
		MybatisColumn column = null;
		sqlBuilder.append("SELECT ");
		String idColumn = null;
		while(it.hasNext()) {
			column = it.next();
			sqlBuilder.append(generationManager.formatColumnName(column.getColumn()));
			if(column.isPrimary()) {
				idColumn = generationManager.formatColumnName(column.getColumn());
			}
			if(it.hasNext()) {
				sqlBuilder.append(",");
			}
		}
		sqlBuilder.append(" FROM ").append(this.getEntityManager().getTablename());
		String id = this.getStatement();
		String sql = sqlBuilder.toString();
		Configuration config = this.getEntityManager().getConfiguration();
		SqlCommandType sqlCommandType  = SqlCommandType.SELECT;
		StaticTextSqlNode textSqlNode = new StaticTextSqlNode(sql);
		String parameter = new StringBuilder().append(MybatisPartTree.GENERIC_NAME_PREFIX).append("1").toString();
		List<SqlNode> whereSqlNodes = new ArrayList<SqlNode>();
		whereSqlNodes.add(new StaticTextSqlNode(new StringBuilder().append(idColumn).append(" in ").toString()));
		whereSqlNodes.add(new ForEachSqlNode(config, new StaticTextSqlNode("#{id}"), parameter, false, "index", "id", "(", ")", ","));
		IfSqlNode ifSqlNode = new IfSqlNode(new MixedSqlNode(whereSqlNodes), new StringBuilder().append(parameter).append(".size > 0").toString());
		WhereSqlNode whereSqlNode = new WhereSqlNode(config, ifSqlNode);
		List<SqlNode> contents = new ArrayList<SqlNode>();
		contents.add(textSqlNode);
		contents.add(whereSqlNode);
		MixedSqlNode sqlNode = new MixedSqlNode(contents);
		SqlSource sqlSource = new DynamicSqlSource(config, sqlNode);
		Class<?> domainClass = this.getEntityManager().getEntityInformation().getJavaType();
		String resultMapName = domainClass.getSimpleName();
		this.getEntityManager().addMappedStatement(id, sqlSource, sqlCommandType, ParamMap.class, resultMapName, domainClass);
	}

}
